package com.douqu.game.auth.utils;

import com.alibaba.fastjson.JSONObject;
import com.douqu.game.auth.database.mapper.RoleRecordMapper;
import com.douqu.game.auth.database.model.RoleRecordModel;
import com.douqu.game.auth.database.model.TdInfoDetail;
import com.douqu.game.auth.server.SpringContext;
import com.douqu.game.core.database.model.AdTalkingDataModel;
import com.douqu.game.core.database.model.OrderRecordModel;
import com.douqu.game.core.database.model.RechargeTalkingDataModel;
import com.douqu.game.core.database.model.TalkingDataModel;
import com.douqu.game.core.factory.LoadFactory;
import com.douqu.game.core.factory.PlatformFactory;
import com.douqu.game.core.protobuf.SGCommonProto;
import com.douqu.game.core.util.CoreUtils;
import com.douqu.game.core.util.LogUtils;
import com.douqu.game.core.util.StringUtils;

import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.Date;
import java.util.Properties;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingDeque;
import java.util.zip.GZIPInputStream;
import java.util.zip.GZIPOutputStream;

/**
 * @author: miracle.
 * Description: talkingData   为了使用interrput只能使用继承Thread
 * Date: 2018/8/1 0001 下午 3:31
 * Huan Yu Copyright (c) 2017 All Rights Reserved.
 */
public class TalkingDataUtils extends Thread {

    public static String DEFAULT_PROTOCOL = "http";
    public static String SLASH = "/";
    public static String COLON = ":";
    public static String DEFAULT_NET_ERROR = "NetError";
    public static String POST = "POST";
    /** recharge参数*/
    public static String TD_OS_ANDROID;
    public static String TD_OS_IOS;
    public static String TD_CURRENCY_TYPE;
    public static String TD_HTTP_ADDRESS;
    public static String TD_HTTP_API;
    public static String TD_APPID;
    public static String TD_REQUEST;
    public static String TD_SUCCESS;

    /** ad参数*/
    public static String AD_URL;
    public static String AD_IOS_APP_KEY;
    public static String AD_ANDROID_APP_KEY;
    //1 android 2 ios
    public static String AD_PAYCURRENCY;

    public static String TALKINGDATA_CONFIG_NAME = "talkingData.properties";

    public static BlockingQueue<TalkingDataModel> bq = new LinkedBlockingDeque<>();

    private static HttpClient rechargeClient;
    private static HttpClient adClient;

    private static RoleRecordMapper roleRecordMapper;

    private HttpClient getRechargeClient(){
        if (rechargeClient == null){
            synchronized (TalkingDataUtils.class){
                if (rechargeClient == null){
                    rechargeClient = new HttpClient();
                    rechargeClient.rechargeClient();
                }
            }
        }
        return rechargeClient;
    }

    private HttpClient getAdClient(){
        if (adClient == null){
            synchronized (TalkingDataUtils.class){
                if (adClient == null){
                    adClient = new HttpClient();
                    adClient.adClinet();
                }
            }
        }
        return adClient;
    }

    //在take不阻塞的时候优雅的关闭线程
    private volatile boolean shutdownThread = false;
    /**
     * 分两步走：
     * 1.先生成预订单 request
     * 2.充值成功 success
     */
    @Override
    public void run() {
        roleRecordMapper = SpringContext.getBean(RoleRecordMapper.class);
        LogUtils.info("init roleRecordSuccess ...");
        LogUtils.info("send recharge message to talkingData Thread Start ...");
        TalkingDataModel model = null;
        HttpClient client = null;
        RoleRecordModel recordModel = null;
        while(true){
            //关闭程序的时候把数据处理完再关闭
            if (shutdownThread && bq.size() == 0){
                break;
            }
            try {
                //如果没有数据可以取到的时候 会阻塞到这里
                model = bq.take();
                //将生成的json对象发送
                client = null;
                boolean flag = false;
                if (model instanceof RechargeTalkingDataModel){
                    recordModel = roleRecordMapper.getByObjectIndex(((RechargeTalkingDataModel) model).getAccountID());
                    if(recordModel == null)
                    {
                        LogUtils.warn("recordModel is null -> " + ((RechargeTalkingDataModel) model).getAccountID());
                        continue;
                    }
                    if (StringUtils.isNullOrEmpty(recordModel.getTdInfo()))
                        continue;
                    initModel(recordModel, (RechargeTalkingDataModel) model);
                    client = getRechargeClient();
                    LogUtils.info("talkingData recharge start...");
                }
                else if (model instanceof AdTalkingDataModel){
                    recordModel = roleRecordMapper.getByObjectIndex(((AdTalkingDataModel) model).getAccount());
                    if(recordModel == null)
                    {
                        LogUtils.warn("recordModel is null -> " + ((AdTalkingDataModel) model).getAccount());
                        continue;
                    }
                    if (StringUtils.isNullOrEmpty(recordModel.getTdInfo()))
                        continue;
                    initTdModel(recordModel, (AdTalkingDataModel) model);
                    client = getAdClient();
                    LogUtils.info("adTract start ...");
                    flag = true;
                }
                else
                {
                    LogUtils.error("不认识的talkingData类 -> model:" + model.toString());
                    continue;
                }

                if (client == null){
                    LogUtils.error("client is null ->: model:" + model.toString());
                    continue;
                }
                String result;
                if (flag){
                    result = doPost1(gzip(JSONObject.toJSONString(model)),client._HttpURLConnection,client.url);
                }else{
                    result = doPost(gzip(JSONObject.toJSONString(model)),client._HttpURLConnection,client.url);
                }
                LogUtils.info(result);
            }catch (Exception e){
                if (e instanceof InterruptedException ){
                    //强制关闭线程
                    LogUtils.info("shutDown talkData Thread Success ...");
                    break;
                }else{
                    e.printStackTrace();
                    LogUtils.errorException(e);
                }
            }
        }
        LogUtils.info("shutDown talkData Thread Success ...");
    }

    //退出线程
    public void shutDown(){
        shutdownThread = true;
        interrupt();
    }

    public static void loadTalkingDataConfig(){
        final String path = LoadFactory.FIXED_CONFIG_PATH + TALKINGDATA_CONFIG_NAME;
        LogUtils.info("【Load talkingData Start FileName = " + path + " 】");
        Properties properties = new Properties();
        InputStream inputStream = null;
        try{
            inputStream = LoadFactory.getInputStream(path);
            properties.load(inputStream);
            TD_OS_ANDROID = properties.get("TD_OS_ANDROID").toString().trim();
            TD_OS_IOS = properties.get("TD_OS_IOS").toString().trim();
            TD_CURRENCY_TYPE = properties.get("TD_CURRENCY_TYPE").toString().trim();
            TD_HTTP_ADDRESS = properties.get("TD_HTTP_ADDRESS").toString().trim();
            TD_HTTP_API = properties.get("TD_HTTP_API").toString().trim();
            TD_APPID = properties.get("TD_APPID").toString().trim();
            TD_REQUEST = properties.get("TD_REQUEST").toString().trim();
            TD_SUCCESS = properties.get("TD_SUCCESS").toString().trim();
            AD_URL = properties.get("AD_URL").toString().trim();
            AD_IOS_APP_KEY = properties.get("AD_IOS_APP_KEY").toString().trim();
            AD_ANDROID_APP_KEY = properties.get("AD_ANDROID_APP_KEY").toString().trim();

            LogUtils.info("TD_OS_ANDROID ----------- 【" + TD_OS_ANDROID + "】");
            LogUtils.info("TD_OS_IOS-----------------【" + TD_OS_IOS + "】");
            LogUtils.info("TD_CURRENCY_TYPE -------- 【" + TD_CURRENCY_TYPE +"】");
            LogUtils.info("TD_HTTP_ADDRESS --------- 【" + TD_HTTP_ADDRESS +"】");
            LogUtils.info("TD_HTTP_API ------------- 【" + TD_HTTP_API +"】");
            LogUtils.info("TD_APPID ---------------- 【" + TD_APPID+"】");
            LogUtils.info("TD_REQUEST--------------- 【" + TD_REQUEST +"】");
            LogUtils.info("TD_SUCCESS--------------- 【" + TD_SUCCESS +"】");
            LogUtils.info("AD_URL--------------------【" + AD_URL + "】");
            LogUtils.info("AD_IOS_APP_KEY------------【" + AD_IOS_APP_KEY + "】");
            LogUtils.info("AD_ANDROID_APP_KEY--------【" + AD_ANDROID_APP_KEY + "】");

            LogUtils.info("Load talkingData Success =======================");
        }catch (Exception e){
            e.printStackTrace();
            LogUtils.errorException(e);
        }finally {
            if (inputStream != null){
                try {
                    inputStream.close();
                }catch (IOException e){
                    e.printStackTrace();
                    LogUtils.errorException(e);
                }
            }
        }
    }

    private static byte[] gzip(String content) throws Exception{
        content = "[" + content + "]";
        content = content.replaceAll("oS","OS");
        LogUtils.info(" json:" + content);
        ByteArrayOutputStream baos = null;
        GZIPOutputStream out = null;
        byte[] ret = null;
        try{
            baos = new ByteArrayOutputStream();
            out = new GZIPOutputStream(baos);
            out.write(content.getBytes());
            out.close();
            baos.close();
            ret = baos.toByteArray();
        }catch (FileNotFoundException e){
            e.printStackTrace();
            throw e;
        }catch (IOException e){
            e.printStackTrace();
            throw e;
        }finally {
            //finally里面的异常不抛出 直接打印不要因为close的异常造成数据没有传输成功的假象 造成重复
            if (out != null){
                try{
                    baos.close();
                }catch (IOException e){
                    e.printStackTrace();
                    LogUtils.errorException(e);
                }
            }
            if (out != null){
                try{
                    out.close();
                }catch (IOException e){
                    e.printStackTrace();
                    LogUtils.errorException(e);
                }
            }
        }
        return ret;
    }

    public class HttpClient{

        HttpURLConnection _HttpURLConnection = null;
        URL url = null;

        public void rechargeClient(){
            try{
                String ServerURL = "";
                ServerURL += DEFAULT_PROTOCOL;
                ServerURL += COLON;
                ServerURL += SLASH;
                ServerURL += SLASH;
                ServerURL += TD_HTTP_ADDRESS;
                if (TD_HTTP_API.charAt(0) != '/'){
                    ServerURL += SLASH;
                }
                ServerURL += TD_HTTP_API;
                ServerURL += SLASH;
                ServerURL += TD_APPID;
                url = new URL(ServerURL);
            }catch (Exception e){
                e.printStackTrace();
                LogUtils.errorException(e);
            }
        }

        public void adClinet(){
            try{
                if(PlatformFactory.IOS.equals(PlatformFactory.SYSTEM_VERSION))
                    url = new URL(AD_URL + SLASH + AD_IOS_APP_KEY + "?");
                else if(PlatformFactory.ANDROID.equals(PlatformFactory.SYSTEM_VERSION))
                    url = new URL(AD_URL + SLASH + AD_ANDROID_APP_KEY + "?");
                else
                {
                    LogUtils.error("系统版本没有配置或者错误 -> SYSTEM_VERSION:" + PlatformFactory.SYSTEM_VERSION);
                }
            }catch (Exception e){
                LogUtils.errorException(e);
            }
        }
    }

    /**
     * 1. 当获取到充值消息的时候先加入到消息队列中
     * 2. take到消息的时候在进行一次包装
     * @param o
     * @return
     */
    public static AdTalkingDataModel initTdModel(OrderRecordModel o){
        AdTalkingDataModel td = new AdTalkingDataModel();
        td.setMsgid(String.valueOf(o.getId()));
        td.setActiontime(new Date().getTime());
        td.setPayamount(o.getMoney());
        td.setPaycurrency(TD_CURRENCY_TYPE);
        td.setPaytype(o.getPaymentType());
        td.setAccount(o.getObjectIndex());
        td.setOrderid(o.getOutTradeNo());
        return td;
    }

    private static AdTalkingDataModel initTdModel(RoleRecordModel recordModel,AdTalkingDataModel td){
        TdInfoDetail tdInfoDetail = recordModel.getTdInfoDetail();
        if (tdInfoDetail.getTdDeviceIdType() == SGCommonProto.E_TD_DEVICEID_TYPE.TD_DEVICEID_ANDROIDID_VALUE){
            td.setPlatform(1);
            td.setAndroidid(tdInfoDetail.getTdDeviceId());
        }
        else if (tdInfoDetail.getTdDeviceIdType() == SGCommonProto.E_TD_DEVICEID_TYPE.TD_DEVICEID_MAC_VALUE){
            td.setPlatform(2);
            td.setMac(tdInfoDetail.getTdDeviceId());
        }
        else if (tdInfoDetail.getTdDeviceIdType() == SGCommonProto.E_TD_DEVICEID_TYPE.TD_DEVICEID_IDFA_VALUE){
            td.setPlatform(2);
            td.setIdfa(tdInfoDetail.getTdDeviceId());
        }
        td.setTdid(tdInfoDetail.getTdid());
        td.setOsversion(tdInfoDetail.getOsversion());
        td.setIp(recordModel.getIp());
        return td;
    }

    public static RechargeTalkingDataModel initModel(OrderRecordModel o) throws Exception{
        RechargeTalkingDataModel td = new RechargeTalkingDataModel();
        if (o.getId() == 0){
            throw new Exception("id is null");
        }
        td.setMsgID(String.valueOf(o.getId()));
        if (StringUtils.isNullOrEmpty(o.getSsid())){
            td.setStatus(TD_REQUEST);
        }else{
            td.setStatus(TD_SUCCESS);
        }
        td.setAccountID(o.getObjectIndex());
        td.setOrderID(o.getOutTradeNo());
        td.setCurrencyAmount((double)o.getMoney()/100L);
        td.setCurrencyType(TD_CURRENCY_TYPE);
        td.setVirtualCurrencyAmount((double)o.getVirtualCurrencyAmount());
        if (o.getCompleteTime() != null){
            td.setChargeTime(o.getCompleteTime().getTime());
        }else{
            td.setChargeTime(o.getCreateTime().getTime());
        }
        td.setIapID(o.getRechargeId() == 0 ?null:String.valueOf(o.getRechargeId()));
        td.setPaymentType(o.getPaymentType());
        td.setGameServer(String.valueOf(o.getServerId()));
        td.setGameVersion(o.getGameVersion());
        td.setLevel(o.getLevel());
        td.setMission(o.getMission());
        int[] result = CoreUtils.formRuleId(o.getPartner());
        String parner = SGCommonProto.E_GAME_NAME.forNumber(result[0]).name().replaceAll("GAME_NAME_","");
        parner = parner + SGCommonProto.E_SERVER_TYPE.forNumber(result[1]).name().replaceAll("SERVER_TYPE_","");
        parner = parner + SGCommonProto.E_PLATFORM_TYPE.forNumber(result[2]).name().replaceAll("PLATFORM_TYPE_","");
        td.setPartner(parner);
        return td;
    }

    public static RechargeTalkingDataModel initModel(RoleRecordModel recordModel,RechargeTalkingDataModel td) throws Exception{
        TdInfoDetail tdInfoDetail = recordModel.getTdInfoDetail();
        if (tdInfoDetail.getTdDeviceIdType() == SGCommonProto.E_TD_DEVICEID_TYPE.TD_DEVICEID_ANDROIDID_VALUE)
            td.setOS(TD_OS_ANDROID);
        else
            td.setOS(TD_OS_IOS);
        return td;
    }

    public String doPost1(byte[] Message,HttpURLConnection _HttpURLConnection,URL url)throws Exception{
        String result = "";
        try {
            _HttpURLConnection = (HttpURLConnection) url.openConnection();
            _HttpURLConnection.setRequestMethod("POST");
            _HttpURLConnection.setDoOutput(true);
            _HttpURLConnection.setRequestProperty("content-encoding", "gzip");
            _HttpURLConnection.setRequestProperty("Content-Type",
                    "application/octet-stream");
            _HttpURLConnection.setRequestProperty("Content-Length", String.valueOf(Message.length));
            DataOutputStream ds = new DataOutputStream(_HttpURLConnection.getOutputStream());
            ds.write(Message);
            ds.flush();
            ds.close();
            InputStream inputStream = _HttpURLConnection.getInputStream();
            byte[] returns = new byte[inputStream.available()];
            inputStream.read(returns);
            result = new String(returns, "UTF-8");
            System.out.println(new String(returns, "UTF-8"));
        }catch (Exception e){
            throw e;
        }finally {
            _HttpURLConnection.disconnect();
        }
        return result;
    }

    public String doPost(byte[] Message,HttpURLConnection _HttpURLConnection,URL url) throws Exception{
        String result = "";
        try {
            _HttpURLConnection = (HttpURLConnection) url.openConnection();
            _HttpURLConnection.setRequestMethod(POST);
            _HttpURLConnection.setDoOutput(true);
            _HttpURLConnection.setRequestProperty("Content-Type",
                    "application/msgpack");
            _HttpURLConnection.setRequestProperty("Content-Length",
                    String.valueOf(Message.length));
            DataOutputStream ds = new DataOutputStream(
                    _HttpURLConnection.getOutputStream());
            ds.write(Message);
            ds.flush();
            ds.close();
            result = _gzipStream2Str(_HttpURLConnection.getInputStream());
        }catch (Exception e){
            throw e;
        }finally {
            _HttpURLConnection.disconnect();
        }
        return result;
    }

    private String _gzipStream2Str(InputStream inputStream) throws IOException{
        GZIPInputStream gzipInputStream = new GZIPInputStream(inputStream);
        byte[] buf = new byte[1024];
        int num = -1;
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        while ((num = gzipInputStream.read(buf,0,buf.length)) != -1){
            baos.write(buf,0,num);
        }
        return new String(baos.toByteArray(),"utf-8");
    }
}
